iT邦幫忙

2024 iThome 鐵人賽

DAY 14
0
Software Development

我的SpringBoot絕學:7+2個專案,從新手變專家系列 第 14

Day14 第五個Spring Boot專案:會員註冊登入系統(4)登出和自訂驗證系統

  • 分享至 

  • xImage
  •  

登出設定

我們在AppConfig.java的formLogin後面再增加以下內容,將登出的網址設定為/logout,以及登出後會轉址到/login?logout

.logout(logout -> logout
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/login?logout"))

修改users.html加入登出按鈕

...
<a th:href="@{/}">Home</a>
<a th:href="@{/logout}">Logout</a>
...

我們在login.html添加登出的訊息,順便增加在登入錯誤時,顯示email或密碼有錯的訊息。

如果網址是login?logout,代表已經登出,顯示You've logged out.

如果是login?error,代表email或密碼有錯,則是Wrong email or password

...
<h3 th:if="${param.logout}">You've logged out.</h3>
<h3 th:if="${param.error}">Wrong email or password</h3>
<form method="post" role="form" th:action="@{/login}">
...

我們啟動專案,嘗試登出,觀察登出後顯示的訊息。

輸入錯誤的密碼,進行登入,可以看到錯誤訊息。

明文儲存密碼的問題

我們先看一下資料庫中儲存的內容,有id、email和密碼,有沒有覺得怪怪的,或許你現在沒那個感覺,但是當我說出答案時就會恍然大悟。

使用大型網站(如Google)時忘記密碼,通常寄來是一封帶有密碼重置連結的email,而小型網站很貼心把原本的密碼寄給我,不用重置密碼讓人感覺很好。

大網站為什麼不這麽做呢?因為大網站是將密碼用雜湊(Hash)函式得到的雜湊數值存進資料庫,他不知道原本的密碼是什麼,只有雜湊數值,使用雜湊數值回推原始的密碼是很困難的一件事,直接重置密碼比較快。

我們的專案現在就像是小型網站的做法,稱呼為明文儲存密碼,把原始密碼存在資料庫中,用戶忘記就能傳給他。

明文儲存有個很大的問題,駭客破解資料庫後就能拿到密碼,接著密碼就會被到處散播,如果Gmail、Facebook也使用相同的密碼,就會發現帳號每天被駭客嘗試登入許多次。

明文儲存對用戶來說太危險了,我們要遠離這種網站,檢驗的方式就是「忘記密碼」,重置的是好網站,回傳明文密碼的是壞網站。

雜湊密碼

我們在Spring Security中開啟雜湊函式,在AppConfig.java加入

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

在UserService.java將密碼雜湊後存入資料庫

public void createUser(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        userRepository.save(user);
    }

這樣用戶的密碼就能被安全的保存了。

自訂登入驗證系統

建立CustomUserDetailsServiceImpl.java,驗證用戶的email和密碼。

//CustomUserDetailsServiceImpl.java

@Service
public class CustomUserDetailsServiceImpl implements UserDetailsService {
    private final UserRepository userRepository;

    public CustomUserDetailsServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

根據email取得用戶的資訊,並驗證email和密碼是否正確

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepository.findUserByEmail(email);

如果找不到用戶,就回傳找不到使用這個email的用戶

if (user == null) {
            throw new UsernameNotFoundException("User not found with email :" + email);
        }

給用戶ROLE_USER權限

List<GrantedAuthority> authorities = List.of(new SimpleGrantedAuthority("ROLE_USER"));

驗證用戶的email和密碼是否正確,正確就可以登入,如果email或密碼有誤拒絕登入。

        return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), authorities);
    }
}

我們刪除資料庫中的舊資料(密碼沒雜湊的部分),啟動MySQL Client (MariaDB (x64)),先查詢哪些用戶的密碼沒經過雜湊

USE user_db;
SELECT * FROM users WHERE password NOT LIKE "$%";

雜湊後的密碼是$開頭的內容,我們尋找密碼不是$開頭的,那些就是舊的資料,顯示在螢幕上。

確認螢幕上的資料沒錯後,刪除舊資料。

在刪除之前先用SELECT查看一下,再DELETE是個好習慣,可以避免成為「MySQL從刪庫到跑路」的主角。

刪除舊用戶

DELETE FROM users WHERE password NOT LIKE "$%";

啟動專案,我們先註冊新用戶再登入,確認新的登入驗證系統正常運作。

我們的專案就完成了。

程式碼

需要自行編寫application.properties

https://mega.nz/file/0NNCkbTL#x0kGEOZESCHaU_dkrVh41dgzT_LYNJ_RPWwmUGPCtA8


上一篇
Day13 第五個Spring Boot專案:會員註冊登入系統(3)登入、Spring Security設定
下一篇
Day15 第六個Spring Boot專案:小型電商購物車系統(1)專案介紹
系列文
我的SpringBoot絕學:7+2個專案,從新手變專家31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言